package ue.client.galaxy;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import ue.client.core.Util;
import ue.client.entities.Entity;

public class Location {
	public static final int MAX_ASTEROIDS = 10;
	
	protected ArrayList<Entity> entities;
	
	protected ArrayList<Asteroid> asteroids;
	
	protected int x, y;
	
	protected final long seed;
	protected String name;
	protected double sunFactor;
	protected int asteroidAmount;
	protected double asteroidValue;
	
	public Location(int x, int y) {
		this.x = x;
		this.y = y;
		
		entities = new ArrayList<Entity>();
		asteroids = new ArrayList<Asteroid>();
		
		seed = generateSeed(x, y);
		
		name = Util.generateName(seed, 0);
		
		generateSystem(seed);
	}
	
	public Location(String path) {
		Document doc = null;
		try {
			doc = new SAXBuilder().build(path);
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		Element root = doc.getRootElement();
		
		if(root.getName() != "location") {
			System.err.println("ERROR: Incorrect XML File: Wrong root name");
			System.exit(1);
		}
		
		asteroids = new ArrayList<Asteroid>();
		entities = new ArrayList<Entity>();
		
		try {
			x = root.getAttribute("x").getIntValue();
			y = root.getAttribute("y").getIntValue();
		} catch (DataConversionException e) {
			e.printStackTrace();
		}
		
		name = root.getChildText("name");
		sunFactor = Double.parseDouble(root.getChildText("sunfactor"));
		asteroidAmount = Integer.parseInt(root.getChildText("asteroidamount"));
		asteroidValue = Double.parseDouble(root.getChildText("asteroidvalue"));
		
		Element asteroids = root.getChild("asteroids");
		List<?> asteroidsElementList = asteroids.getChildren("asteroid");
		
		for(int i = 0; i < asteroidsElementList.size(); i++) {
			this.asteroids.add(new Asteroid((Element)asteroidsElementList.get(i)));
		}
		
		seed = generateSeed(x, y);
	}
	
	public Location(int x, int y, String name, double sunFactor,
			int asteroidAmount, double asteroidValue,
			ArrayList<Asteroid> asteroids) {
		this.x = x;
		this.y = y;
		this.name = name;
		seed = generateSeed(x, y);
		this.sunFactor = sunFactor;
		this.asteroidAmount = asteroidAmount;
		this.asteroidValue = asteroidValue;
		this.asteroids = asteroids;
	}

	//Seed Generation
	public static long generateSeed(int x, int y) {
		if(x == 0 && y == 0) return 0;
		
		long n = Math.abs(x) + Math.abs(y);
		
		long seed = 2 * (n - 1) * n;
		
		if(x >= 0 && y >= 0) {
			seed += (x + 1);
		} else if(x >= 0 && y < 0) {
			seed += (n + 1) + n - x;
		} else if(x < 0 && y <= 0) {
			seed += (n + 1) + n - x;
		} else {
			seed += (n + 1) + 2 * n + x + n + 1;
		}
		
		return seed;
	}

	//System Generation
	protected void generateSystem(long seed) {
		Random random = new Random(seed);
		
		random.nextDouble();
		
		sunFactor = random.nextDouble();
		
		asteroidAmount = random.nextInt(MAX_ASTEROIDS);
		asteroidValue = random.nextDouble();
		
		/*for(int i = 0; i < asteroidAmount; i++) {
			asteroids.add(new Asteroid(random.nextInt(), asteroidValue));
		}*/
	}
	
	public void addEntity(Entity entity) {
		entities.add(entity);
	}
	
	public void removeEntity(int i) {
		entities.remove(i);
	}
	
	public void removeEntity(Entity entity) {
		entities.remove(entity);
	}
	
	public void clearEntities() {
		entities.clear();
	}
	
	@Override
	public String toString() {
		String tmp = "Name: " + name + "\n"
				+ "SunFactor: " + sunFactor + "\n"
				+ "AsteroidAmount: " + asteroidAmount + "\n"
				+ "AsteroidValue: " + asteroidValue + "\n";
		
		for(int i = 0; i < asteroids.size(); i++) {
			tmp += asteroids.get(i).toString() + "\n";
		}
		
		return tmp;
	}
	
	public int saveToXMLFile(String path) {
		Document doc = new Document();
		
		Element location = new Element("location");
		location.setAttribute("x", "" + x);
		location.setAttribute("y", "" + y);
		
		Element name = new Element("name");
		name.setText(this.name);
		
		Element sunFactor = new Element("sunfactor");
		sunFactor.setText("" + this.sunFactor);
		
		Element asteroidAmount = new Element("asteroidamount");
		asteroidAmount.setText("" + this.asteroidAmount);
		
		Element asteroidValue = new Element("asteroidvalue");
		asteroidValue.setText("" + this.asteroidValue);
		
		Element asteroids = new Element("asteroids");
		
		for(int i = 0; i < this.asteroids.size(); i++) {
			asteroids.addContent(this.asteroids.get(i).toXMLElement());
		}
		
		location.addContent(name);
		location.addContent(sunFactor);
		location.addContent(asteroidAmount);
		location.addContent(asteroidValue);
		location.addContent(asteroids);
		
		doc.addContent(location);
		
		File file = new File(path);
		
		try {
			PrintStream stream = new PrintStream(file);
			
			XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
			try {
				out.output(doc, stream);
			} catch (IOException e) {
				e.printStackTrace();
			}
			stream.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		
		return 0;
	}

	public ArrayList<Entity> getEntities() {
		return entities;
	}

	public void setEntities(ArrayList<Entity> entities) {
		this.entities = entities;
	}

	public ArrayList<Asteroid> getAsteroids() {
		return asteroids;
	}

	public void setAsteroids(ArrayList<Asteroid> asteroids) {
		this.asteroids = asteroids;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getSunFactor() {
		return sunFactor;
	}

	public void setSunFactor(double sunFactor) {
		this.sunFactor = sunFactor;
	}

	public int getAsteroidAmount() {
		return asteroidAmount;
	}

	public void setAsteroidAmount(int asteroidAmount) {
		this.asteroidAmount = asteroidAmount;
	}

	public double getAsteroidValue() {
		return asteroidValue;
	}

	public void setAsteroidValue(double asteroidValue) {
		this.asteroidValue = asteroidValue;
	}

	public long getSeed() {
		return seed;
	}
}
